﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DataAccessClasses
{
    public class DataAccessLayer
    {
        private TicketsDataClassesDataContext context;

        public DataAccessLayer()
        {
            context = new TicketsDataClassesDataContext();
        }

        public System.Data.Linq.Table<Event> Events
        {
            get
            {
                return context.Events;
            }
        }

        public System.Data.Linq.Table<Location> Locations
        {
            get
            {
                return context.Locations;
            }
        }

        public System.Data.Linq.Table<Category> Categories
        {
            get
            {
                return context.Categories;
            }
        }

        public System.Data.Linq.Table<Purchase> Purchases
        {
            get
            {
                return context.Purchases;
            }
        }

        public TicketsDataClassesDataContext GlobalContext
        {
            get
            {
                return context;
            }
        }

        public void SaveChanges()
        {
            context.SubmitChanges();
        }
 

        public void CreateCategory(string categoryName)
        {
            if (categoryName == null || categoryName.Length <= 0 || categoryName.Length > 50)
                throw new ArgumentException("Invalid argument!");

            Category cat = new Category();
            cat.CategoryName = categoryName;
            context.Categories.InsertOnSubmit(cat);
            context.SubmitChanges();
        }

        public void ModifyCategory(int categoryId, string newCategoryName)
        {
            Category cat = (from c in context.Categories
                            where c.CategoryID == categoryId
                            select c).SingleOrDefault();
            if (cat != null)
            {
                cat.CategoryName = newCategoryName;
                context.SubmitChanges();
            }
            else
            {
                throw new ArgumentException("No such category!");
            }
        }

        public void DeleteCategory(int categoryId)
        { 
            int count = (from e in context.Events
                         where e.CategoryID == categoryId
                         select e).Count();

            if (count > 0)
            {
                throw new ArgumentException("Cannot delete category! Selected category is used in some events.");
            }
            else
            {
                Category cat = (from c in context.Categories
                                where c.CategoryID == categoryId
                                select c).SingleOrDefault();
                if (cat == null)
                {
                    throw new ArgumentException("No such category!");
                }
                else
                {
                    context.Categories.DeleteOnSubmit(cat);
                    context.SubmitChanges();
                }
            }
            context = new TicketsDataClassesDataContext();
        }

        public void CreateLocation(string locationName)
        { 
            if (locationName == null || locationName.Length <= 0 || locationName.Length > 50)
                throw new ArgumentException("Invalid argument!");

            Location location = new Location();
            location.LocationName = locationName;
            context.Locations.InsertOnSubmit(location);
            context.SubmitChanges();
        }

        public void ModifyLocation(int locationId, string newLocationName)
        { 
            Location location = (from loc in context.Locations
                                 where loc.LocationID == locationId
                                 select loc).SingleOrDefault();
            if (location != null)
            {
                location.LocationName = newLocationName;
                context.SubmitChanges();
            }
            else
            {
                throw new ArgumentException("No such location!");
            }
        }

        public void DeleteLocation(int locationId)
        { 
            int count = (from e in context.Events
                         where e.LocationID == locationId
                         select e).Count();

            if (count > 0)
            {
                throw new ArgumentException("Cannot delete location! Selected location is used in some events.");
            }
            else
            {
                Location location = (from loc in context.Locations
                                     where loc.LocationID == locationId
                                     select loc).SingleOrDefault();
                if (location == null)
                {
                    throw new ArgumentException("No such location!");
                }
                else
                {
                    context.Locations.DeleteOnSubmit(location);
                    context.SubmitChanges();
                }
            }
            context = new TicketsDataClassesDataContext();
        }

        public void CreateEvent(int categoryId, int locationId, string title, DateTime date, decimal price)
        { 
            int cats = (from c in context.Categories
                        where c.CategoryID == categoryId
                        select c).Count();
            if (cats == 0)
            {
                throw new ArgumentException("No such category!");
            }

            int locs = (from c in context.Locations
                        where c.LocationID == locationId
                        select c).Count();
            if (locs == 0)
            {
                throw new ArgumentException("No such Location!");
            }

            if (title == null || title.Length == 0 || title.Length > 50)
            {
                throw new ArgumentException("Invalid title!");
            }

            Event e = new Event();
            e.LocationID = locationId;
            e.CategoryID = categoryId;
            e.Title = title;
            e.Date = date;
            e.Price = price;

            context.Events.InsertOnSubmit(e);
            context.SubmitChanges();
        }

        public void ModifyEvent(int eventId,int categoryId, int locationId, string title, DateTime date, decimal price)
        { 
            int cats = (from c in context.Categories
                        where c.CategoryID == categoryId
                        select c).Count();
            if (cats == 0)
            {
                throw new ArgumentException("No such category!");
            }

            int locs = (from c in context.Locations
                        where c.LocationID == locationId
                        select c).Count();
            if (locs == 0)
            {
                throw new ArgumentException("No such Location!");
            }

            if (title == null || title.Length == 0 || title.Length > 50)
            {
                throw new ArgumentException("Invalid title!");
            }

            Event e = (from ev in context.Events
                       where ev.EventID == eventId
                       select ev).SingleOrDefault();
            if (e == null)
            {
                throw new ArgumentException("No such event!");
            }
            else
            {
                e.LocationID = locationId;
                e.CategoryID = categoryId;
                e.Title = title;
                e.Date = date;
                e.Price = price;
                context.SubmitChanges();
            }
       
        }

        public void DeleteEvent(int eventId)
        { 
            Event ev = (from e in context.Events
                       where e.EventID == eventId
                       select e).SingleOrDefault();
            if (ev == null)
            {
                throw new ArgumentException("No such event!");
            }
            else
            {
                context.Events.DeleteOnSubmit(ev);
                context.SubmitChanges();
            }
            context = new TicketsDataClassesDataContext();
        }

        public IQueryable<Event> FindUpcomingEvents(int? categoryId)
        {
            
            var result = from c in context.Events
                         where (categoryId == null || c.CategoryID == categoryId)
                                && c.Date>=DateTime.Now.AddDays(3)
                         orderby c.Date ascending
                         select c;
            return result;
        }

        public int CreatePurchase(int eventId,string customer,string address,int ticketCount)
        { 
            if (customer == null || customer.Length > 50 || address == null || address.Length > 50 || ticketCount <= 0)
            {
                throw new ArgumentException("Invalid arguments!");
            }
            
            int eventCnt = (from c in context.Events
                            where c.EventID == eventId
                            select c).Count();
            if (eventCnt == 0)
            {
                throw new ArgumentException("No such event!");
            }

            Purchase p = new Purchase();
            p.EventID = eventId;
            p.CustomerName = customer;
            p.ShippingAddress = address;
            p.TicketCount = ticketCount;
            p.Status = OrderStatus.Ordered;
            context.Purchases.InsertOnSubmit(p);
            context.SubmitChanges();
            
            return p.PurchaseID;
        }

        public IQueryable<Purchase> FindPurchases(int? purchaseId,OrderStatus status)
        {
            var result = from p in context.Purchases
                         where (purchaseId == null || p.PurchaseID == purchaseId)
                         && (status == OrderStatus.Unspecified || p.Status == status)
                         select p;
            return result;
        }

        public void ChangePurchaseStatus(int purchaseId,OrderStatus status)
        { 
            Purchase purchase = (from p in context.Purchases
                                where p.PurchaseID == purchaseId
                                select p).SingleOrDefault();
            if (purchase == null)
            {
                throw new ArgumentException("No such order!");
            }
            else
            {
                purchase.Status = status;
                context.SubmitChanges();
            }
        }
    }
}
